﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Serialization;
using Vcm;

namespace Ankha_VCM_GUI
{
    public partial class MainForm : Form
    {
        private const string SettingsRelativePath = "AVCM\\";
        private const string FormSettingsFileName = "AVCM.xml";

        private FormSettings _formSettings = new FormSettings();

        public MainForm()
        {
            InitializeComponent();
            LoadFormSettings();
            UpdateControlsWithSettings();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            var version = DataImport.GetVersion();
            Text += string.Format(" v. {0}", version);
        }

        private void btBrowseInputFile_Click(object sender, EventArgs e)
        {
            if (inputOpenFileDialog.ShowDialog() == DialogResult.OK)
                tbInputFile.Text = inputOpenFileDialog.FileName;
        }

        private void btBrowseOutputFile_Click(object sender, EventArgs e)
        {
            if (outputSaveFileDialog.ShowDialog() == DialogResult.OK)
                tbOutputFile.Text = outputSaveFileDialog.FileName;
        }

        private void btBrowseArtworkFolder_Click(object sender, EventArgs e)
        {
            if (artworkFolderBrowserDialog.ShowDialog() == DialogResult.OK)
                tbArtworkFolder.Text = artworkFolderBrowserDialog.SelectedPath;
        }

        private void btBrowseExpansionSetSymbolPath_Click(object sender, EventArgs e)
        {
            if (expansionSymbolOpenFileDialog.ShowDialog() == DialogResult.OK)
                tbExpansionSetSymbolPath.Text = expansionSymbolOpenFileDialog.FileName;
        }

        private void btGenerate_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(tbInputFile.Text))
            {
                MessageBox.Show("Please select a CSV input file.", "No file selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            _formSettings.InputFileName = tbInputFile.Text.Trim();

            if (!File.Exists(_formSettings.InputFileName))
            {
                MessageBox.Show(string.Format("Couldn't open file {0}", _formSettings.InputFileName), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (string.IsNullOrWhiteSpace(tbOutputFile.Text))
            {
                _formSettings.OutputFileName = cbGhostMode.Checked
                    ? string.Format("{0}\\{1}-ghost.pdf", Path.GetDirectoryName(_formSettings.InputFileName), Path.GetFileNameWithoutExtension(_formSettings.InputFileName))
                    : Path.ChangeExtension(_formSettings.InputFileName, "pdf");
                var message = string.Format("No output file specified, will write in file {0}", _formSettings.OutputFileName);
                if (MessageBox.Show(message, "Confirm default output file name", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    return;
            }
            else
            {
                _formSettings.OutputFileName = tbOutputFile.Text.Trim();
            }

            if (File.Exists(_formSettings.OutputFileName))
            {
                var message = string.Format("File {0} already exists. Do you want to replace it?", _formSettings.OutputFileName);
                if (MessageBox.Show(message, "Confirm file replacement", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.Cancel)
                    return;
            }

            var csvDelimiter = tbCsvDelimiter.Text.Trim();
            if (csvDelimiter.Length != 1)
            {
                MessageBox.Show("CSV delimiter must be 1 character long. White Wolf's CSV files used comma ',' but Excel prefers semi column ';'. Other characters are nevertheless supported.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            _formSettings.CsvDelimiter = csvDelimiter[0];

            _formSettings.WatermarkOpacity = (int)nudWatermarkOpacity.Value;
            if (_formSettings.WatermarkOpacity < 0 || _formSettings.WatermarkOpacity > 100)
            {
                MessageBox.Show("The watermark opacity value must be within the 0 (transparent) - 100 (opaque) range", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            _formSettings.ExpansionSetSymbolPath = tbExpansionSetSymbolPath.Text.Trim();
            if (_formSettings.ExpansionSetSymbolPath.Length == 0)
                _formSettings.ExpansionSetSymbolPath = null;

            _formSettings.Watermark = tbWatermark.Text.Trim();
            _formSettings.WatermarkPosition = (CardPosition)cbWatermarkPosition.SelectedIndex;
            _formSettings.WatermarkOrientation = (TextOrientation)cbWatermarkOrientation.SelectedIndex;
            _formSettings.WatermarkColor = pnlWatermarkColor.BackColor.ToArgb() & 0x00FFFFFF;
            _formSettings.ArtworkFolder = tbArtworkFolder.Text;
            _formSettings.CopyrightText = tbCopyrightText.Text.Trim();
            _formSettings.UseGhost = cbGhostMode.Checked;
            _formSettings.NotForLegalPlay = cbNotForLegalPlay.Checked;
            _formSettings.CardsPerPage = Convert.ToInt32(cbCardsPerPage.SelectedItem);

            _formSettings.FormWidth = this.Width;
            _formSettings.FormHeight = this.Height;
            _formSettings.FormLeft = this.Left;
            _formSettings.FormTop = this.Top;

            SaveFormSettings();

            Generate();
        }

        private void UpdateControlsWithSettings()
        {
            tbInputFile.Text = _formSettings.InputFileName;
            tbOutputFile.Text = _formSettings.OutputFileName;
            tbArtworkFolder.Text = _formSettings.ArtworkFolder;
            tbCsvDelimiter.Text = _formSettings.CsvDelimiter.ToString();
            tbCopyrightText.Text = _formSettings.CopyrightText;
            tbWatermark.Text = _formSettings.Watermark;
            cbWatermarkPosition.SelectedIndex = (int)_formSettings.WatermarkPosition;
            cbWatermarkOrientation.SelectedIndex = (int)_formSettings.WatermarkOrientation;
            pnlWatermarkColor.BackColor = Color.FromArgb((_formSettings.WatermarkColor & 0xFF0000) >> 16, (_formSettings.WatermarkColor & 0x00FF00) >> 8, _formSettings.WatermarkColor & 0x0000FF);
            nudWatermarkOpacity.Value = _formSettings.WatermarkOpacity;
            tbExpansionSetSymbolPath.Text = _formSettings.ExpansionSetSymbolPath;
            cbGhostMode.Checked = _formSettings.UseGhost;
            cbNotForLegalPlay.Checked = _formSettings.NotForLegalPlay;
            cbCardsPerPage.SelectedIndex = cbCardsPerPage.Items.IndexOf(_formSettings.CardsPerPage.ToString());

            if (_formSettings.FormWidth.HasValue || _formSettings.FormHeight.HasValue || _formSettings.FormLeft.HasValue || _formSettings.FormTop.HasValue)
            {
                StartPosition = FormStartPosition.Manual;
                Width = _formSettings.FormWidth ?? Width;
                Height = _formSettings.FormHeight ?? Height;
                Left = _formSettings.FormLeft ?? Left;
                Top = _formSettings.FormTop ?? Top;
            }
        }

        private void LoadFormSettings()
        {
            var path = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), SettingsRelativePath);
            var filePath = path + FormSettingsFileName;
            if (!File.Exists(filePath))
                return;

            try
            {
                using (var stream = File.Open(filePath, FileMode.Open))
                {
                    var xmlSerializer = new XmlSerializer(typeof(FormSettings));
                    _formSettings = (FormSettings)xmlSerializer.Deserialize(stream);
                    stream.Close();
                }
            }
            catch (Exception)
            {
                return; // probably an old version of the settings
            }
        }

        private void SaveFormSettings()
        {
            var path = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), SettingsRelativePath);
            Directory.CreateDirectory(path);

            using (var stream = File.Open(path + FormSettingsFileName, FileMode.Create))
            {
                var xmlSerializer = new XmlSerializer(typeof(FormSettings));
                xmlSerializer.Serialize(stream, _formSettings);
                stream.Close();
            }
        }

        private void Generate()
        {
            rtbOutputMessages.Clear();
            rtbOutputMessages.ForeColor = Color.Black;
            ProxyDocument doc = null;
            try
            {
                WriteOutputMessage("Importing source file " + _formSettings.InputFileName);
                var data = DataImport.ImportCsv(_formSettings.InputFileName, _formSettings.CsvDelimiter);

                WriteOutputMessage("Creating output file " + _formSettings.OutputFileName);
                doc = ProxyDocument.CreateProxiesPdf(_formSettings.OutputFileName, _formSettings.ArtworkFolder, _formSettings.CopyrightText, _formSettings.Watermark, _formSettings.WatermarkPosition, _formSettings.WatermarkOrientation, _formSettings.WatermarkColor, _formSettings.WatermarkOpacity, _formSettings.ExpansionSetSymbolPath, _formSettings.UseGhost, _formSettings.NotForLegalPlay, _formSettings.CardsPerPage);

                ICardMaker cardMaker = null;
                foreach (DataRow row in data.Rows)
                {
                    if (row.ItemArray.All(item => item.ToString().Trim().Length == 0)) // skip empty lines
                        continue;

                    if (cardMaker == null)
                    {
                        cardMaker = new LibraryCardMaker();
                        if (!cardMaker.SupportsRow(row))
                        {
                            cardMaker = new CryptCardMaker();
                            if (!cardMaker.SupportsRow(row))
                                throw new Exception("Row format is not supported. Check that the columns are correct.");
                        }
                    }

                    //if (!row["name"].ToString().Equals("Scout Youngwood", StringComparison.InvariantCultureIgnoreCase))
                    //    continue;

                    string outputMessage;
                    cardMaker.AddCard(doc, row, out outputMessage);
                    WriteOutputMessage(outputMessage);
                }
                if (cardMaker != null)
                    cardMaker.DrawCutLines(doc);
            }
            catch (Exception e)
            {
                rtbOutputMessages.ForeColor = Color.Red;
                rtbOutputMessages.AppendText("Error detected:" + Environment.NewLine);
                rtbOutputMessages.AppendText(e.Message + Environment.NewLine);
                rtbOutputMessages.AppendText(e.StackTrace + Environment.NewLine);
                if (doc != null)
                    ProxyDocument.EnsureDocumentCanBeClosed(doc);
            }
            finally
            {
                if (doc != null)
                {
                    WriteOutputMessage("Closing output file.");
                    ProxyDocument.SaveAndCloseProxiesPdf(doc);
                }
            }
            WriteOutputMessage("Done.");
        }

        private void WriteOutputMessage(string message)
        {
            rtbOutputMessages.AppendText(message + Environment.NewLine);
            rtbOutputMessages.ScrollToCaret();
            Application.DoEvents();
        }

        private void pnlWatermarkColor_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                pnlWatermarkColor.BackColor = colorDialog1.Color;
            }
        }

        private void btnFixCsv_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(tbInputFile.Text))
            {
                MessageBox.Show("Please select a CSV input file.", "No file selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            _formSettings.InputFileName = tbInputFile.Text.Trim();

            if (!File.Exists(_formSettings.InputFileName))
            {
                MessageBox.Show(string.Format("Couldn't open file {0}", _formSettings.InputFileName), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            var csvDelimiter = tbCsvDelimiter.Text.Trim();
            if (csvDelimiter.Length != 1)
            {
                MessageBox.Show("CSV delimiter must be 1 character long. White Wolf's CSV files used comma ',' but Excel prefers semi column ';'. Other characters are nevertheless supported.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            _formSettings.CsvDelimiter = csvDelimiter[0];

            _formSettings.FormWidth = this.Width;
            _formSettings.FormHeight = this.Height;
            _formSettings.FormLeft = this.Left;
            _formSettings.FormTop = this.Top;

            SaveFormSettings();

            FixCsv();
        }

        private void FixCsv()
        {
            rtbOutputMessages.Clear();
            rtbOutputMessages.ForeColor = Color.Black;
            try
            {
                WriteOutputMessage("Importing source file " + _formSettings.InputFileName);
                var data = DataImport.ImportCsv(_formSettings.InputFileName, _formSettings.CsvDelimiter, clearErrataSymbols: false);

                var outputFilename = _formSettings.InputFileName + ".fixed";

                WriteOutputMessage("Creating output file " + outputFilename);

                ICardMaker cardMaker = null;
                using (var outputFile = new StreamWriter(outputFilename, false, System.Text.Encoding.Default))
                {
                    var columnNames = data.Columns.Cast<object>().Select(column => column.ToString());
                    outputFile.WriteLine(string.Join(",", columnNames));
                    foreach (DataRow row in data.Rows)
                    {
                        if (row.ItemArray.All(item => item.ToString().Trim().Length == 0)) // skip empty lines
                            continue;

                        if (cardMaker == null)
                        {
                            cardMaker = new LibraryCardMaker();
                            if (!cardMaker.SupportsRow(row))
                            {
                                cardMaker = new CryptCardMaker();
                                if (!cardMaker.SupportsRow(row))
                                    throw new Exception("Row format is not supported. Check that the columns are correct.");
                            }
                        }

                        string outputMessage;
                        cardMaker.FixCard(outputFile, row, out outputMessage);
                        if(!string.IsNullOrEmpty(outputMessage))
                            WriteOutputMessage(outputMessage);
                    }
                }
            }
            catch (Exception e)
            {
                rtbOutputMessages.ForeColor = Color.Red;
                rtbOutputMessages.AppendText("Error detected:" + Environment.NewLine);
                rtbOutputMessages.AppendText(e.Message + Environment.NewLine);
                rtbOutputMessages.AppendText(e.StackTrace + Environment.NewLine);
            }
            finally
            {
            }
            WriteOutputMessage("Done.");
        }

    }
}
